﻿using System;
using System.Linq;
using System.Collections.Generic;
using CoolCode.Data;
using CoolCode.Models;
using CoolCode.Services;
using CoolCode.Bracket.LinqToSql.Entities;

namespace CoolCode.Bracket.LinqToSql.Services
{
    public class MenuService : ServiceBase, IMenuService
    {
        #region Data Access Object

        private IRepository<Menu> _MenuDao;
        public IRepository<Menu> MenuDao
        {
            get
            {
                if (_MenuDao == null)
                {
                    _MenuDao = this.CreateRepository<Menu>();
                }
                return _MenuDao;
            }
            set
            {
                _MenuDao = value;
            }
        }

        private IRepository<MenuInRole> _MenuInRoleDao;
        public IRepository<MenuInRole> MenuInRoleDao
        {
            get
            {
                if (_MenuInRoleDao == null)
                {
                    _MenuInRoleDao = this.CreateRepository<MenuInRole>();
                }
                return _MenuInRoleDao;
            }
            set
            {
                _MenuInRoleDao = value;
            }
        }

        private IRepository<MenuInUser> _MenuInUserDao;
        public IRepository<MenuInUser> MenuInUserDao
        {
            get
            {
                if (_MenuInUserDao == null)
                {
                    _MenuInUserDao = this.CreateRepository<MenuInUser>();
                }
                return _MenuInUserDao;
            }
            set
            {
                _MenuInUserDao = value;
            }
        }

        #endregion

        public MenuService()
            : base()
        {
            this.LoadWith<MenuInRole>(c => c.Menu)
                .LoadWith<MenuInUser>(c => c.Menu)
                .EndLoad();
        }

        public ModuleList ListMenu(string user)
        {
            return this.ListMenu(user, "System");
        }

        public ModuleList ListMenu(string user, string type)
        {
            ModuleList list = new ModuleList();
            var menuList = this.MenuDao.Where(c => c.Type == type).OrderBy(c => c.Seq).ToList();

            MenuModel perentMenu1 = null;
            MenuModel perentMenu2 = null;
            if (menuList.Count > 0)
            {
                foreach (var menu in menuList)
                {
                    MenuModel model = new MenuModel
                    {
                        ID = menu.ID,
                        Name = menu.Name,
                        Title = menu.Desc,
                        Enabled = true,// 
                        ModuleId = menu.ModuleID,
                        Seq = menu.Seq,
                        Type = menu.Type,
                        Level = (menu.ID % 10000 == 0 ? 0 : (menu.ID % 100 == 0 ? 1 : 2)),
                        Target = menu.Target

                    };
                    switch (model.Level)
                    {
                        case 0:
                            perentMenu1 = model;
                            list.Add(model);
                            break;
                        default:
                            if (model.Level == 1)
                            {
                                perentMenu2 = model;
                                perentMenu1.Children.Add(model);
                            }
                            else if (model.Level == 2)
                            {
                                perentMenu2.Children.Add(model);
                            }
                            break;
                    }
                }
            }
            return list;
        }

        public List<RoleModel> ListMenuInRole(string role)
        {
            string lowerRoleName = role.ToLower(); 

            var query = from m in this.MenuDao
                        from mu in this.MenuInRoleDao
                        where mu.RoleName == lowerRoleName && m.ID == mu.MenuID 
                        orderby mu.MenuID
                        select new RoleModel
                        {
                            MenuID = mu.MenuID,
                            MenuDesc = mu.Menu.Desc,
                            Authority = mu.Authority,
                        };
            var list = query.ToList();
            if (list.Count == 0)
            {
                list = this.MenuDao.Where(c => c.ParentID > 0).OrderBy(c => c.Seq)
                     .Select(m => new RoleModel
                     {
                         MenuID = m.ID,
                         MenuDesc = m.Desc,
                     }).ToList();
            }
            list.ForEach(c =>
            {
                c.BelongTo = lowerRoleName;
                c.CanRead = (c.Authority & 0x1) != 0;
                c.CanWrite = (c.Authority & 0x2) != 0;
                c.CanDelete = (c.Authority & 0x4) != 0;
                c.CanExport = (c.Authority & 0x8) != 0;
            });
            return list;
        }

        public void DeleteMenuInRole(string role)
        {
            this.MenuInRoleDao.Delete(c => c.RoleName == role.ToLower());
            this.Submit();
        }

        public void SaveMenuInRole(List<RoleModel> list)
        {
            if (list.Count == 0) return;
            this.MenuInRoleDao.Delete(c => c.RoleName == list.First().BelongTo.ToLower());
            var menuInRole = list.Select(c => new MenuInRole
             {
                 MenuID = c.MenuID,
                 RoleName = c.BelongTo.ToLower(),
                 Authority = (short)((c.CanRead ? 0x1 : 0) + (c.CanWrite ? 0x2 : 0) + (c.CanDelete ? 0x4 : 0) + (c.CanExport ? 0x8 : 0)),
             });
            this.MenuInRoleDao.Insert(menuInRole);
            this.Submit();
        }

        public List<RoleModel> ListMenuInUser(string user)
        {
            string lowerUserName = user.ToLower(); 

            var query = from m in this.MenuDao
                        from mu in this.MenuInUserDao
                        where mu.UserName == lowerUserName && m.ID == mu.MenuID
                        orderby mu.MenuID
                        select new RoleModel
                        {
                            MenuID = mu.MenuID,
                            MenuDesc = mu.Menu.Desc,
                            Authority = mu.Authority,
                            CanRead = false,
                            CanWrite = false,
                            CanDelete = false,
                            CanExport = false,
                        };
            var list = query.ToList();
            if (list.Count == 0)
            {
                query = from mr in this.MenuInRoleDao
                        where mr.RoleName == Role.DefaultUserRole.ToLower()
                        orderby mr.MenuID
                        select new RoleModel
                        {
                            MenuID = mr.MenuID,
                            MenuDesc = mr.Menu.Desc,
                            Authority = mr.Authority,
                            CanRead = false,
                            CanWrite = false,
                            CanDelete = false,
                            CanExport = false,
                        };
                list = query.ToList();
            }
            if (list.Count == 0)
            {
                list = this.MenuDao.Where(c => c.ParentID > 0).OrderBy(c => c.Seq)
                     .Select(m => new RoleModel
                     {
                         MenuID = m.ID,
                         MenuDesc = m.Desc,
                     }).ToList();
            }
            list.ForEach(c =>
            {
                c.BelongTo = lowerUserName;
                c.CanRead = (c.Authority & 0x1) != 0;
                c.CanWrite = (c.Authority & 0x2) != 0;
                c.CanDelete = (c.Authority & 0x4) != 0;
                c.CanExport = (c.Authority & 0x8) != 0;
            });
            return list;
        }

        public void DeleteMenuInUser(string user)
        {
            this.MenuInUserDao.Delete(c => c.UserName == user.ToLower());
            this.Submit();
        }

        public void SaveMenuInUser(List<RoleModel> list)
        {
            if (list.Count == 0) return;
            this.MenuInUserDao.Delete(c => c.UserName == list.First().BelongTo.ToLower());
            var menuInUser = list.Select(c => new MenuInUser
            {
                MenuID = c.MenuID,
                UserName = c.BelongTo.ToLower(),
                Authority = (short)((c.CanRead ? 0x1 : 0) + (c.CanWrite ? 0x2 : 0) + (c.CanDelete ? 0x4 : 0) + (c.CanExport ? 0x8 : 0)),
            });
            this.MenuInUserDao.Insert(menuInUser);
            this.Submit();
        }

        public Role GetRoleByPage(string user, string module, string node)
        {
            int authority = 0;
            var entity = this.MenuInUserDao.FirstOrDefault(c => c.UserName == user.ToLower() &&
                c.Menu.ModuleID == module && c.Menu.Name == node);
            if (entity != null)
            {
                authority = entity.Authority;
            }
            else
            {
                var query = from c in this.MenuInRoleDao
                            where c.RoleName == Role.DefaultUserRole.ToLower() &&
                             c.Menu.ModuleID == module && c.Menu.Name == node
                            select c.Authority;
                authority = query.FirstOrDefault();
            }
            return new Role
            {
                AllowAccess = (authority & 0x1) != 0,
                AllowEdit = (authority & 0x2) != 0,
                AllowDelete = (authority & 0x4) != 0,
                AllowExport = (authority & 0x8) != 0,
            };
        }

    }
}

